#!/usr/bin/python2.4
#
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.
import glob
import optparse
import os
import re
import shutil
import tempfile
import cherrypy

from custom_field_storage import CustomFieldStorage

# pylint: disable-msg=C6409
def noBodyProcess():
  """Overrides default Cherrypy handling to give direct control of submission.

  Sets cherrypy.request.process_request_body = False, giving us direct control
  of the file upload destination. By default cherrypy loads it to memory, we are
  directing it to disk.
  """

  cherrypy.request.process_request_body = False

# Override the default Cherrypy body processing in favor of noBodyProcess()
cherrypy.tools.noBodyProcess = cherrypy.Tool('before_request_body',
                                             noBodyProcess)

class Admin:
  def __init__(self, data_dir='./data/', forms_dir='./forms/',
               allowed_file_types='xml,jpg,png'):
    """Creates data and forms directories, sets allowed upload file types.

    Args:
      data_dir: A string containing the base path to the directory where
        POSTed data is saved
      forms_dir: A string containing the base path where forms downloadable by
        ODK Collect are stored
      allowed_file_types: A list of strings of allowed file extensions defining
        file types from the ODK Collect submission that will be stored on disk.

    Returns:
      Cherrypy reponse: HTTP 201 and "Location" header to client and the
        repsonse body as HTML string summarizing the files uploaded.
    """

    self.data_dir = data_dir
    self.forms_dir = forms_dir

  @cherrypy.expose  
  @cherrypy.tools.noBodyProcess()
  def index(self, d=None, file1=None, file2=None):
    html_response = ''
    
    if d:
      # try to delete the specified file if possible
      try:
        os.remove(os.path.join(self.forms_dir, d))
      except:
        pass
  
    if cherrypy.request.method.upper() == 'POST':
      # Default cherrypy timeout is 300s. Increased to 1hr for large files.
      cherrypy.response.timeout = 3600

      # Convert the header keys to lower case
      lc_headers = dict([k.lower(), v] for (k, v) in
                        cherrypy.request.headers.iteritems())

      # At this point we could limit the upload on content-length...
      # incomingBytes = int(lc_headers['content-length'])

      # Create our version of cgi.FieldStorage to parse the MIME encoded
      # form data where the file is contained
      form_fields = CustomFieldStorage(fp=cherrypy.request.rfile,
                                       headers=lc_headers,
                                       environ={'REQUEST_METHOD': 'POST'},
                                       keep_blank_values=True)

      for field in form_fields:
        form_file = form_fields[field]
        ext = os.path.splitext(form_file.filename)[1]
        #remove the dot from the file extension
        ext = ext.replace('.', '')

        # Prevent filenames that could cause moving up a directory
        target_file = form_file.filename.replace('../', '').replace('..\\', '')
        target_file_path = os.path.join(self.forms_dir, target_file)

        # If the file is really small (> 1KB), the cgi module loads it
        # as a cStringIO object, which has no "name" property,
        # which causes an AttributeError in original code sample.
        # So we must detect if this is a stringIO object instead of a tempfile:
        html_response += "file " + target_file_path
        if not hasattr(form_file.file, 'name'):
          # Write contents of stringIO object to target file
          f = open(target_file_path, 'w+b')
          f.write(form_file.file.getvalue())
          f.close()
          form_file.file.close()
        else:
          # For tempfiles, move to the target location
          form_file.file.close()
          shutil.move(form_file.file.name, target_file_path)
        html_response += 'Stored: %s<br>' % target_file_path
  
    form_list_xml = '<ul>\n'
    for xml_form in glob.glob(os.path.join(self.forms_dir, '*.xml')):
      xml_form_base = os.path.basename(xml_form)
      # Shave off the .xml extension to get the form name
      form_name = os.path.splitext(xml_form_base)[0]
      form_list_xml += '<li>%s [<a href="?d=%s">del</a>]</li>\n' % (form_name, os.path.basename(xml_form))
    form_list_xml += '</ul>\n'
  
    return """
<html>
<body>
  <h3>ODK python server - Upload form</h3>
  <p></p>
  <p>Upload forms. %s</p>
  <form action="?" method="post" enctype="multipart/form-data">
      File: <input type="file" name="file1"/> <br/>
      <input type="submit"/>
  </form>
  <p><b>Current forms:</b></p>
  %s
</body>
</html>
    """ % (html_response, form_list_xml)

    
